Skip to content

Conversation

@AA-Turner
Copy link
Member

@AA-Turner AA-Turner commented Jun 5, 2022

Goes from 916 to 650 errors with strict_optional = True.

Feature or Bugfix

  • Bugfix
  • Refactoring

xref: #10528

A

@AA-Turner
Copy link
Member Author

cc: @danieleades

A

@AA-Turner AA-Turner added this to the 5.x milestone Jun 5, 2022
Copy link
Contributor

@danieleades danieleades left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there's a few blanket warnings suppressions that can be tightened, although these are technically adjacent to the changed code

supported_data_uri_images = False

def __init__(self, app: "Sphinx") -> None:
def __init__(self, app: "Sphinx", env: BuildEnvironment = None) -> None:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
def __init__(self, app: "Sphinx", env: BuildEnvironment = None) -> None:
def __init__(self, app: "Sphinx", env: Optional[BuildEnvironment] = None) -> None:

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here I'm using None as a sentinel, I could have equally used .... I don't want to indicate to users that None is a valid type, which I believe using Optional[] syntax would do. Hence I'm -1 on both these suggestions, unless you've alternate ideas?

A

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that's not how this works. Setting a default value of None effectively coerces the type from Type to Optional[Type]. That is, the former desugars to the latter implicitly. The setting that controls this is called no-implicit-optional.

It's better to be explicit and use the Optional. If using 'strict' mypy checking, failing to use it becomes a hard error.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added no_implicit_optional = True and everything still passes -- is this what you meant?

A

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, it should be an error with that config. Not sure why you're not seeing one, could be you're hitting the maximum number of errors, or it could be a false negative. In either case you should be able to convince yourself from the documentation that using the explicit Optional is strictly correct.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah i think i see the issue. you have this-

strict_optional = False
no_implicit_optional = True

to see these errors your would need

strict_optional = True
no_implicit_optional = True

if you really want to give yourself nightmares, try

strict = True


def __init__(self, app: Sphinx) -> None:
super().__init__(app)
def __init__(self, app: Sphinx, env: BuildEnvironment = None) -> None:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
def __init__(self, app: Sphinx, env: BuildEnvironment = None) -> None:
def __init__(self, app: Sphinx, env: Optional[BuildEnvironment] = None) -> None:

f"'env'argument. Report this bug to the developers of your custom builder, "
f"this is likely not a issue with Sphinx. The 'env' argument will be required "
f"from Sphinx 7.", RemovedInSphinx70Warning, stacklevel=2)
return self.builders[name](app)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • The new code never calls set_environment(). As a result, custom builders will get crashed because the env object is None.
  • This will also cause another warning on Builder.__init__(). The users will see warnings twice or more.

Please be careful to changing the API. I believe Sphinx is not only an application but also a framework. So I consider this is a mix of refactoring and API changing. Is it intended?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was concerned the potential to call set_environment twice, but it seems that wouldn't be a problem, so updated. I also added a check so that we only issue one warning.

Please be careful to changing the API. I believe Sphinx is not only an application but also a framework. So I consider this is a mix of refactoring and API changing. Is it intended?

This PR shouldn't have any end-user facing changes. I would say I consider Sphinx more of an application with a plugin mechanism though, rather than a library/framework -- we should be able to make changes that improve things on our end, although of course seeking to keep backwards compatability.

A

@danieleades
Copy link
Contributor

@AA-Turner this is already a herculean effort, nice work!

If you're not able to squash all of the errors in this PR, you may want to consider whitelisting a subset of files with strict_optional = False, so that the CI checks can run on the rest. Then the whitelist can be incrementally shrunk in subsequent PRs. See my comment over here - #10528 (comment)

that would look something like

current:

[mypy]
python_version = 3.6
disallow_incomplete_defs = True
show_column_numbers = True
show_error_context = True
ignore_missing_imports = True
follow_imports = skip
check_untyped_defs = True
warn_unused_ignores = True
strict_optional = False

new:

[mypy]
python_version = 3.6
disallow_incomplete_defs = True
show_column_numbers = True
show_error_context = True
ignore_missing_imports = True
follow_imports = skip
check_untyped_defs = True
warn_unused_ignores = True

[mypy-some.module]
strict_optional = False

[mypy-some.other.module]
strict_optional = False

(i think? i usually use pyproject.toml for configuring mypy)

@AA-Turner
Copy link
Member Author

I'm not going to do the whitelist approach -- I got to 34 modules and the list is ridiculous (100+ lines long) and there are still 244 errors reported.

My progress is in the details block for posterity, but I don't reccomend adding it to setup.cfg.

Details
strict_optional = True
no_implicit_optional = True

[mypy-sphinx.application]
strict_optional = False

[mypy-sphinx.writers.latex]
strict_optional = False

[mypy-sphinx.builders.latex]
strict_optional = False

[mypy-sphinx.builders.html]
strict_optional = False

[mypy-sphinx.builders.gettext]
strict_optional = False

[mypy-sphinx.builders.singlehtml]
strict_optional = False

[mypy-sphinx.builders.dirhtml]
strict_optional = False

[mypy-sphinx.builders.latex.transforms]
strict_optional = False

[mypy-sphinx.domains.c]
strict_optional = False

[mypy-sphinx.domains.cpp]
strict_optional = False

[mypy-sphinx.domains.javascript]
strict_optional = False

[mypy-sphinx.domains.python]
strict_optional = False

[mypy-sphinx.domains.changeset]
strict_optional = False

[mypy-sphinx.builders.xml]
strict_optional = False

[mypy-sphinx.builders.manpage]
strict_optional = False

[mypy-sphinx.builders.texinfo]
strict_optional = False

[mypy-sphinx.writers.texinfo]
strict_optional = False

[mypy-sphinx.writers.text]
strict_optional = False

[mypy-sphinx.writers.html5]
strict_optional = False

[mypy-sphinx.writers.html]
strict_optional = False

[mypy-sphinx.environment]
strict_optional = False

[mypy-sphinx.environment.adapters.indexentries]
strict_optional = False

[mypy-sphinx.util.docfields]
strict_optional = False

[mypy-sphinx.directives.code]
strict_optional = False

[mypy-sphinx.transforms.post_transforms.images]
strict_optional = False

[mypy-sphinx.builders.linkcheck]
strict_optional = False

[mypy-sphinx.ext.autosummary]
strict_optional = False

[mypy-sphinx.ext.autodoc]
strict_optional = False

[mypy-sphinx.ext.apidoc]
strict_optional = False

[mypy-sphinx.ext.autosummary.generate]
strict_optional = False

[mypy-sphinx.ext.imgmath]
strict_optional = False

[mypy-sphinx.ext.intersphinx]
strict_optional = False

[mypy-sphinx.ext.mathjax]
strict_optional = False

[mypy-sphinx.ext.graphviz]
strict_optional = False

[mypy-sphinx.ext.inheritance_diagram]
strict_optional = False

A

@AA-Turner
Copy link
Member Author

Followup:

If you're not able to squash all of the errors in this PR

This PR was never about getting all of them, it started as ensuring MyPy passes on Windows and then I fixed some "easy" targets. C.f. Zen, pragmatism & purity...!

A

@AA-Turner AA-Turner changed the title Fix static typing issues on Windows; increase Optional strictness Increase static typing strictness Jun 16, 2022
@AA-Turner AA-Turner merged commit 6ef22d2 into sphinx-doc:5.x Jun 16, 2022
@AA-Turner AA-Turner deleted the typing-strictness branch June 16, 2022 18:50
@AA-Turner AA-Turner modified the milestones: 5.x, 5.1.0 Jun 16, 2022
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Jul 17, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants